//
//  SortableController+DestinationRow.swift
//
//  Created by 谢强 on 16/03/2018.
//  Copyright © 2018 谢强. All rights reserved.
//

import UIKit

fileprivate extension CGRect {
    init(center: CGPoint, size: CGSize) {
        self.init(
            x: center.x - (size.width * 0.5),
            y: center.y - (size.height * 0.5),
            width: size.width,
            height: size.height
        )
    }
}

// MARK: - 终止位置设置
extension SortableController {
    
    func destinationRow_update() {
        guard
            case SortState.updating(let context) = sortState,
            let tableView = tableView,
            let proposedIndexPath = destinationRow_proposedIndexPath(),
            let newDestination = delegate?.jw_tableView(tableView, targetIndexPathFromRowAt: context.sourceRow, to: proposedIndexPath),
            newDestination != context.destinationRow
        else { return }
        
        var newContext = context
        newContext.destinationRow = newDestination
        sortState = SortState.updating(context: newContext)
        delegate?.jw_tableView(tableView, fromRowAt: context.destinationRow, to: newContext.destinationRow)
        
        tableView.beginUpdates()
        tableView.deleteRows(at: [context.destinationRow], with: .fade)
        tableView.insertRows(at: [newContext.destinationRow], with: .fade)
        tableView.endUpdates()
    }
    
    private func destinationRow_proposedIndexPath() -> IndexPath? {
        // 校验
        guard
            case SortState.updating(let context) = sortState,
            let tableView = tableView,
            let superview = tableView.superview,
            let snapshotView = snapshotView
        else { return nil }
        
        let snapshot_frameInSuperview = CGRect(center: snapshotView.center, size: snapshotView.bounds.size)
        let snapshot_frameInTableView = superview.convert(snapshot_frameInSuperview, to: tableView)
        
        // TODO: - <iOS11Bug>
//        let visibleCells = tableView.visibleCells
        let visibleCells = tableView.visibleCells.filter {
            // Workaround for an iOS 11 bug.
            
            // When adding a row using UITableView.insertRows(...), if the new
            // row's frame will be partially or fully outside the table view's
            // bounds, and the new row is not the first row in the table view,
            // it's inserted without animation.
            
            let cellOverlapsTopBounds = $0.frame.minY < tableView.bounds.minY + 5
            let cellIsFirstCell = tableView.indexPath(for: $0) == IndexPath(row: 0, section: 0)
            
            return !cellOverlapsTopBounds || cellIsFirstCell
        }
        
        // snapshotView跟每个cell的距离
        let rowDistances = visibleCells.map { cell -> (path: IndexPath, distance: CGFloat) in
            
            let indexPath = tableView.indexPath(for: cell) ?? IndexPath(row: 0, section: 0)
            
            if context.destinationRow.compare(indexPath) == .orderedAscending {
                return (indexPath, abs(snapshot_frameInTableView.maxY - cell.frame.maxY))
            } else {
                return (indexPath, abs(snapshot_frameInTableView.minY - cell.frame.minY))
            }
        }
        
        // 单独处理分组头部
        let sections = 0..<tableView.numberOfSections
        let sectionDistances = sections.flatMap { section -> (path: IndexPath, distance: CGFloat)? in
            let rowsInSection = tableView.numberOfRows(inSection: section)
            
            if section > context.destinationRow.section {
                let rect: CGRect
                let toIndexPath = IndexPath(row: 0, section: section)
                if rowsInSection == 0 { // 没有内容
                    rect = rectForEmptySection(section)
                } else { // 有内容
                    rect = tableView.rectForRow(at: toIndexPath)
                }
                return (toIndexPath, abs(snapshot_frameInTableView.maxY - rect.minY))
            }
            else if section < context.destinationRow.section {
                let rect: CGRect
                if rowsInSection == 0 {
                    rect = rectForEmptySection(section)
                } else {
                    rect = tableView.rectForRow(at: IndexPath(row: rowsInSection - 1, section: section))
                }
                let toIndexPath = IndexPath(row: rowsInSection, section: section)
                return (toIndexPath, abs(snapshot_frameInTableView.minY - rect.maxY))
            } else {
                return nil
            }
        }
        
        let distances = rowDistances + sectionDistances
        return distances.min(by: { $0.distance < $1.distance})?.path
    }
    
    private func rectForEmptySection(_ section: Int) -> CGRect {
        guard let tableView = tableView else { return CGRect.zero }
        
        let sectionRect = tableView.rectForHeader(inSection: section)
        return UIEdgeInsetsInsetRect(sectionRect, UIEdgeInsets(top: sectionRect.height, left: 0, bottom: 0, right: 0))
    }
}
